﻿using Google.Protobuf;
using System;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Actor.Net.Network.Gate.Adapter
{
    /// <summary>
    /// 消息适配器基类
    /// </summary>
    /// <typeparam name="TRequestMessage"></typeparam>
    /// <typeparam name="TResponseMessage"></typeparam>
    public abstract class GateMessageAdapterAsync<TRequestMessage, TResponseMessage> : GateMessageAdapter<TRequestMessage>
        where TRequestMessage : class, new()
    {
        /// <summary>
        /// 网络IO接口
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requestMessage"></param>
        public override async void OnRequest(GateTransferContext context, TRequestMessage requestMessage)
        {
            try
            {
                var output = await this.OnRequestMessageAsync(context, requestMessage);
                context.Response(output);
            }
            catch (Exception ex)
            {
                context.ChannelContext.Channel.NetService.ProcessSocketError(context.ChannelContext, ex);
            }
        }

        /// <summary>
        /// 异步消息处理接口
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public abstract Task<TResponseMessage> OnRequestMessageAsync(GateTransferContext context, TRequestMessage requestMessage);
    }

    /// <summary>
    /// 消息适配器基类
    /// </summary>
    /// <typeparam name="TRequestMessage"></typeparam>
    /// <typeparam name="TResponseMessage"></typeparam>
    public abstract class GateMessageAdapter<TRequestMessage, TResponseMessage> : GateMessageAdapter<TRequestMessage>
        where TRequestMessage : class, new()
    {
        /// <summary>
        /// 网络IO接口
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requestMessage"></param>
        public override void OnRequest(GateTransferContext context, TRequestMessage requestMessage)
        {
            try
            {
                var output = this.OnRequestMessage(context, requestMessage);
                context.Response(output);
            }
            catch(Exception ex)
            {
                context.ChannelContext.Channel.NetService.ProcessSocketError(context.ChannelContext, ex);
            }
        }

        /// <summary>
        /// 同步消息处理接口
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requestMessage"></param>
        /// <returns></returns>
        public abstract TResponseMessage OnRequestMessage(GateTransferContext context, TRequestMessage requestMessage);
    }

    /// <summary>
    /// 消息适配器基类
    /// </summary>
    /// <typeparam name="TRequestMessage"></typeparam>
    public abstract class GateMessageAdapter<TRequestMessage> : IGateMessageAdapter<TRequestMessage>
        where TRequestMessage : new()
    {
        /// <summary>
        /// 网络IO接口
        /// </summary>
        /// <param name="context"></param>
        /// <param name="requestMessage"></param>
        public abstract void OnRequest(GateTransferContext context, TRequestMessage requestMessage);

        /// <summary>
        /// 消息分发
        /// </summary>
        /// <param name="context"></param>
        public void DispatchAdapter(GateTransferContext context)
        {
            try
            {
                TRequestMessage inputMessage = default;
                var type = typeof(TRequestMessage);
                if (type == typeof(byte[]))
                {
                    var len = (int)context.ReceiveBodyStream.Length;
                    object bytes = new byte[len];
                    context.ReceiveBodyStream.Read(bytes as byte[], 0, len);
                    inputMessage = (TRequestMessage)bytes;
                }
                else if (type == typeof(string))
                {
                    var len = (int)context.ReceiveBodyStream.Length;
                    var bytes = new byte[context.ReceiveBodyStream.Length];
                    context.ReceiveBodyStream.Read(bytes, 0, bytes.Length);
                    object str = Encoding.UTF8.GetString(bytes);
                    inputMessage = (TRequestMessage)str;
                }
                else
                {
                    if (context.ChannelContext.Channel.Network.SerializationType == SerializationType.Protobuf)
                    {
                        inputMessage = (TRequestMessage)new MessageParser(() => (IMessage)new TRequestMessage()).ParseFrom(context.ReceiveBodyStream);
                    }
                    else if (context.ChannelContext.Channel.Network.SerializationType == SerializationType.MessagePack)
                    {
                        inputMessage = MessagePack.MessagePackSerializer.Deserialize<TRequestMessage>(context.ReceiveBodyStream);
                    }
                }

                this.OnRequest(context, inputMessage);
            }
            catch (Exception ex)
            {
                context.ChannelContext.Channel.NetService.ProcessSocketError(context.ChannelContext, ex);
            }
        }
    }
}